layout.tsx 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  1. import Image from "next/image";
  2. import { Inter, Permanent_Marker } from "next/font/google";
  3. import { GeistSans } from "geist/font/sans";
  4. import { GeistMono } from "geist/font/mono";
  5. import { cn } from "@/shared/lib/utils";
  6. import { getServerUrl } from "@/shared/lib/server-url";
  7. import { FB_PIXEL_ID } from "@/shared/lib/facebook/fb-pixel";
  8. import { SiteConfig } from "@/shared/config/site-config";
  9. import { WorkoutSessionsSynchronizer } from "@/features/workout-session/ui/workout-sessions-synchronizer";
  10. import { Header } from "@/features/layout/Header";
  11. import { Footer } from "@/features/layout/Footer";
  12. import { TailwindIndicator } from "@/components/utils/TailwindIndicator";
  13. import { NextTopLoader } from "@/components/ui/next-top-loader";
  14. import FacebookPixel from "@/components/FacebookPixel";
  15. import { Providers } from "./providers";
  16. import type { ReactElement } from "react";
  17. import type { Metadata } from "next";
  18. import "@/shared/styles/globals.css";
  19. export const metadata: Metadata = {
  20. title: SiteConfig.title,
  21. description: SiteConfig.description,
  22. metadataBase: new URL(getServerUrl()),
  23. };
  24. const inter = Inter({
  25. subsets: ["latin"],
  26. variable: "--font-inter",
  27. display: "swap",
  28. });
  29. const permanentMarker = Permanent_Marker({
  30. weight: "400",
  31. subsets: ["latin"],
  32. variable: "--font-permanent-marker",
  33. display: "swap",
  34. });
  35. export const preferredRegion = ["fra1", "sfo1", "iad1"];
  36. interface RootLayoutProps {
  37. params: Promise<{ locale: string }>;
  38. children: ReactElement;
  39. }
  40. export default async function RootLayout({ params, children }: RootLayoutProps) {
  41. const { locale } = await params;
  42. return (
  43. <>
  44. <html className="h-full" dir="ltr" lang={locale} suppressHydrationWarning>
  45. <head>
  46. <meta charSet="UTF-8" />
  47. <meta content="width=device-width, initial-scale=1" name="viewport" />
  48. {/* SEO */}
  49. <meta content="index, follow" name="robots" />
  50. <meta content="Workout Cool" name="author" />
  51. {/* Favicon */}
  52. <link href="/apple-touch-icon.png" rel="apple-touch-icon" sizes="180x180" />
  53. <link href="/images/favicon-32x32.png" rel="icon" sizes="32x32" type="image/png" />
  54. <link href="/images/favicon-16x16.png" rel="icon" sizes="16x16" type="image/png" />
  55. <link href="/images/favicon.ico" rel="shortcut icon" />
  56. {/* Open Graph */}
  57. <meta content={SiteConfig.title} property="og:title" />
  58. <meta content={SiteConfig.description} property="og:description" />
  59. <meta content={"https://www.workout.cool"} property="og:url" />
  60. <meta content="website" property="og:type" />
  61. <meta content={`${getServerUrl()}/images/default-og-image_${locale}.png`} property="og:image" />
  62. {/* Twitter */}
  63. <meta content="summary_large_image" name="twitter:card" />
  64. <meta content="@workout_cool" name="twitter:site" />
  65. <meta content={SiteConfig.title} name="twitter:title" />
  66. <meta content={SiteConfig.description} name="twitter:description" />
  67. <meta content={`${getServerUrl()}/images/default-og-image_${locale}.png`} name="twitter:image" />
  68. {/* Canonical */}
  69. <link href="https://www.workout.cool" rel="canonical" />
  70. {/* Open Graph Locale */}
  71. <meta content={locale === "fr" ? "fr_FR" : "en_US"} property="og:locale" />
  72. <meta content="fr_FR" property="og:locale:alternate" />
  73. <meta content="en_US" property="og:locale:alternate" />
  74. <noscript>
  75. <Image
  76. alt="Facebook Pixel"
  77. height="1"
  78. src={`https://www.facebook.com/tr?id=${FB_PIXEL_ID}&ev=PageView&noscript=1`}
  79. style={{ display: "none" }}
  80. width="1"
  81. />
  82. </noscript>
  83. </head>
  84. <body
  85. className={cn(
  86. "flex flex-col justify-between items-center p-8 min-h-screen max-sm:p-0 max-sm:min-h-full text-sm/[22px] font-normal text-black antialiased dark:text-gray-500",
  87. GeistMono.variable,
  88. GeistSans.variable,
  89. inter.variable,
  90. permanentMarker.variable,
  91. )}
  92. style={{
  93. backgroundImage:
  94. "radial-gradient(circle at 82% 60%, rgba(59, 59, 59,0.06) 0%, rgba(59, 59, 59,0.06) 69%,transparent 69%, transparent 100%),radial-gradient(circle at 36% 0%, rgba(185, 185, 185,0.06) 0%, rgba(185, 185, 185,0.06) 59%,transparent 59%, transparent 100%),radial-gradient(circle at 58% 82%, rgba(183, 183, 183,0.06) 0%, rgba(183, 183, 183,0.06) 17%,transparent 17%, transparent 100%),radial-gradient(circle at 71% 32%, rgba(19, 19, 19,0.06) 0%, rgba(19, 19, 19,0.06) 40%,transparent 40%, transparent 100%),radial-gradient(circle at 77% 5%, rgba(31, 31, 31,0.06) 0%, rgba(31, 31, 31,0.06) 52%,transparent 52%, transparent 100%),radial-gradient(circle at 96% 80%, rgba(11, 11, 11,0.06) 0%, rgba(11, 11, 11,0.06) 73%,transparent 73%, transparent 100%),radial-gradient(circle at 91% 59%, rgba(252, 252, 252,0.06) 0%, rgba(252, 252, 252,0.06) 44%,transparent 44%, transparent 100%),radial-gradient(circle at 52% 82%, rgba(223, 223, 223,0.06) 0%, rgba(223, 223, 223,0.06) 87%,transparent 87%, transparent 100%),radial-gradient(circle at 84% 89%, rgba(160, 160, 160,0.06) 0%, rgba(160, 160, 160,0.06) 57%,transparent 57%, transparent 100%),linear-gradient(90deg, rgb(254,242,164),rgb(166, 255, 237))",
  95. }}
  96. suppressHydrationWarning
  97. >
  98. <Providers locale={locale}>
  99. <WorkoutSessionsSynchronizer />
  100. <NextTopLoader color="#FF5722" delay={100} showSpinner={false} />
  101. {/* Main Card Container */}
  102. <div className="card bg-base-100 shadow-xl w-full max-w-3xl max-sm:rounded-none max-sm:h-full">
  103. <div className="card-body p-0">
  104. <Header />
  105. <div className="px-2 sm:px-6 pb-6">{children}</div>
  106. </div>
  107. <Footer />
  108. </div>
  109. <TailwindIndicator />
  110. <FacebookPixel />
  111. </Providers>
  112. </body>
  113. </html>
  114. </>
  115. );
  116. }